package com.laiketui.common.utils.tool;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.laiketui.common.utils.okhttp.HttpUtils;
import com.laiketui.core.cache.RedisUtil;
import com.laiketui.core.common.LaiKeGlobleConst;
import com.laiketui.core.common.SplitUtils;
import com.laiketui.core.domain.LaiKeApi;
import com.laiketui.core.domain.Result;
import com.laiketui.core.exception.LaiKeAPIException;
import com.laiketui.core.lktconst.GloabConst;
import com.laiketui.core.lktconst.gwconst.LaiKeGWConst;
import com.laiketui.core.utils.tool.DataUtils;
import com.laiketui.domain.lktconst.ErrorCode;
import com.laiketui.root.gateway.dto.LaiKeApiDto;
import com.laiketui.root.gateway.impl.APIServiceFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

/**
 * 远程调用
 *
 * @author Trick
 * @date 2022/7/27 15:37
 */
@Component
public class HttpApiUtils {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private APIServiceFactory serviceFactory;

    /**
     * 内部接口调用
     *
     * @param apiKey -
     * @param params -
     * @return Map
     * @throws LaiKeAPIException-
     * @author Trick
     * @date 2022/7/27 15:50
     */
    public Map<String, Object> executeApi(String apiKey, String params) throws LaiKeAPIException {
        Map<String, Object> resultMap = new HashMap<>(1);
        try {
            logger.debug("调用dubbo:{},参数:{}", apiKey, params);
            String apiCacheKey = LaiKeGlobleConst.RedisCacheKeyPre.LAIKE_API + SplitUtils.UNDERLIEN + apiKey + SplitUtils.UNDERLIEN + LaiKeGWConst.API_VERSION;
            LinkedList<LaiKeApi> apis = DataUtils.cast(redisUtil.get(apiCacheKey));
            if (apis == null) {
                throw new LaiKeAPIException(ErrorCode.ContainerErrorCode.GW_API_NOT_EXISTENT, "接口不存在");
            }
            LaiKeApiDto dto = new LaiKeApiDto();
            dto.setParams(params);
            Result result = serviceFactory.getGatewayService(apis.get(0).getProtocol()).invoke(apis.get(0), dto);
            if (result.getCode().equals(LaiKeGWConst.GW_SUCCESS)) {
                String data = result.getData().toString();
                if (!GloabConst.ManaValue.MANA_VALUE_SUCCESS.equals(data)) {
                    resultMap = JSON.parseObject(result.getData().toString(), new TypeReference<Map<String, Object>>() {
                    });
                }
            } else {
                throw new LaiKeAPIException(result.getCode(), result.getMessage(), "executeApi");
            }
        } catch (Exception e) {
            logger.error("远程调用{} 异常", apiKey, e);
            throw new LaiKeAPIException(ErrorCode.ContainerErrorCode.GW_API_EXECUTE_FAIL, e.getMessage(), "executeApi");
        }
        return resultMap;
    }

    /**
     * http普通调用方式
     *
     * @param apiKey    -
     * @param params    -
     * @param mediaType -传输数据的编码方式
     * @return Map
     * @throws LaiKeAPIException-
     * @author Trick
     * @date 2023/4/17 20:49
     */
    public Map<String, Object> executeHttpApi(String apiKey, Map<String, Object> params, String mediaType) throws LaiKeAPIException {
        Map<String, Object> resultMap = new HashMap<>(1);
        try {
            logger.debug("调用api:{},参数:{}", apiKey, params);
            String apiCacheKey = LaiKeGlobleConst.RedisCacheKeyPre.LAIKE_API + SplitUtils.UNDERLIEN + apiKey + SplitUtils.UNDERLIEN + LaiKeGWConst.API_VERSION;
            LinkedList<LaiKeApi> apis = DataUtils.cast(redisUtil.get(apiCacheKey));
            if (apis == null) {
                throw new LaiKeAPIException(ErrorCode.ContainerErrorCode.GW_API_NOT_EXISTENT, "接口不存在");
            }
            LaiKeApi api = apis.get(0);
            String json = "";
            switch (mediaType) {
                case MediaType.APPLICATION_FORM_URLENCODED_VALUE:
                case MediaType.MULTIPART_FORM_DATA_VALUE:
                    json = HttpUtils.postFormData(api.getUri(), params);
                    break;
                default:
                    json = HttpUtils.post(api.getUri(), JSON.toJSONString(params));
            }

            System.out.println(json);
            Result result = JSONObject.parseObject(json, Result.class);
            if (result.getCode().equals(LaiKeGWConst.GW_SUCCESS)) {
                String data = result.getData().toString();
                if (!GloabConst.ManaValue.MANA_VALUE_SUCCESS.equals(data)) {
                    resultMap = JSON.parseObject(result.getData().toString(), new TypeReference<Map<String, Object>>() {
                    });
                }
            } else {
                throw new LaiKeAPIException(result.getCode(), result.getMessage(), "executeApi");
            }
        } catch (Exception e) {
            logger.error("远程调用{} 异常", apiKey, e);
            throw new LaiKeAPIException(ErrorCode.ContainerErrorCode.GW_API_EXECUTE_FAIL, e.getMessage(), "executeApi");
        }
        return resultMap;
    }

    public Map<String, Object> executeHttpApi(String apiKey, Map<String, Object> params) throws LaiKeAPIException {
        try {
            return executeHttpApi(apiKey, params, MediaType.APPLICATION_JSON_VALUE);
        } catch (Exception e) {
            logger.error("远程调用{} 异常", apiKey, e);
            throw new LaiKeAPIException(ErrorCode.ContainerErrorCode.GW_API_EXECUTE_FAIL, e.getMessage(), "executeApi");
        }
    }

}
